/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
 */

package pl.droidsonroids.gif;

import ohos.aafwk.ability.DataAbilityHelper;
import ohos.aafwk.ability.DataAbilityRemoteException;
import ohos.global.resource.NotExistException;
import ohos.global.resource.RawFileDescriptor;
import ohos.global.resource.RawFileEntry;
import ohos.global.resource.ResourceManager;
import ohos.global.resource.WrongTypeException;
import ohos.utils.net.Uri;

import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.concurrent.ScheduledThreadPoolExecutor;

public abstract class InputSource {
	private InputSource() {
	}

	abstract GifInfoHandle open() throws IOException, DataAbilityRemoteException;

	final GifDrawable createGifDrawable(final GifDrawable oldDrawable, final ScheduledThreadPoolExecutor executor,
										final boolean isRenderingAlwaysEnabled, final GifOptions options) throws IOException, DataAbilityRemoteException {

		return new GifDrawable(createHandleWith(options), oldDrawable, executor, isRenderingAlwaysEnabled);
	}

	final GifInfoHandle createHandleWith(GifOptions options) throws IOException, DataAbilityRemoteException {
		final GifInfoHandle handle = open();
		handle.setOptions(options.inSampleSize, options.inIsOpaque);
		return handle;
	}

	/**
	 * Input using {@link ByteBuffer} as a source. It must be direct.
	 */
	public static final class DirectByteBufferSource extends InputSource {
		private final ByteBuffer byteBuffer;

		/**
		 * Constructs new source.
		 * Buffer can be larger than size of the GIF data. Bytes beyond GIF terminator are not accessed.
		 *
		 * @param byteBuffer source buffer, must be direct
		 */
		public DirectByteBufferSource(ByteBuffer byteBuffer) {
			this.byteBuffer = byteBuffer;
		}

		@Override
		GifInfoHandle open() throws GifIOException {
			return new GifInfoHandle(byteBuffer);
		}
	}

	/**
	 * Input using byte array as a source.
	 */
	public static final class ByteArraySource extends InputSource {
		private final byte[] bytes;

		/**
		 * Constructs new source.
		 * Array can be larger than size of the GIF data. Bytes beyond GIF terminator are not accessed.
		 *
		 * @param bytes source array
		 */
		public ByteArraySource(byte[] bytes) {
			this.bytes = bytes;
		}

		@Override
		GifInfoHandle open() throws GifIOException {
			return new GifInfoHandle(bytes);
		}
	}

	/**
	 * Input using {@link File} or path as source.
	 */
	public static final class FileSource extends InputSource {
		private final String mPath;

		/**
		 * Constructs new source.
		 *
		 * @param file source file
		 */
		public FileSource(File file) {
			mPath = file.getPath();
		}

		/**
		 * Constructs new source.
		 *
		 * @param filePath source file path
		 */
		public FileSource(String filePath) {
			mPath = filePath;
		}

		@Override
		GifInfoHandle open() throws GifIOException {
			return new GifInfoHandle(mPath);
		}
	}

	public static final class UriSource extends InputSource {
		private final DataAbilityHelper mContentResolver;
		private final Uri mUri;

		public UriSource(DataAbilityHelper contentResolver, Uri uri) {
			mContentResolver = contentResolver;
			mUri = uri;
		}

		@Override
		GifInfoHandle open() throws IOException, DataAbilityRemoteException {
			return GifInfoHandle.openUri(mContentResolver, mUri);
		}
	}

	/**
	 * Input using asset as source.
	 */
	public static final class AssetSource extends InputSource {
		private final RawFileEntry mAssetManager;
		private final String mAssetName;

		public AssetSource(RawFileEntry rawFileEntry, String assetName) {
			mAssetManager = rawFileEntry;
			mAssetName = assetName;
		}

		@Override
		GifInfoHandle open() throws IOException {
			return new GifInfoHandle(mAssetManager.openRawFileDescriptor());
		}
	}

	/**
	 * Input using {@link FileDescriptor} as a source.
	 */
	public static final class FileDescriptorSource extends InputSource {
		private final FileDescriptor mFd;

		/**
		 * Constructs new source.
		 *
		 * @param fileDescriptor source file descriptor
		 */
		public FileDescriptorSource(FileDescriptor fileDescriptor) {
			mFd = fileDescriptor;
		}

		@Override
		GifInfoHandle open() throws IOException {
			return new GifInfoHandle(mFd);
		}
	}

	/**
	 * Input using {@link InputStream} as a source.
	 */
	public static final class InputStreamSource extends InputSource {
		private final InputStream inputStream;

		/**
		 * Constructs new source.
		 *
		 * @param inputStream source input stream, it must support marking
		 */
		public InputStreamSource(InputStream inputStream) {
			this.inputStream = inputStream;
		}

		@Override
		public GifInfoHandle open() throws IOException {
			return new GifInfoHandle(inputStream);
		}
	}

	/**
	 * Input using resource (raw or drawable) as a source.
	 */
	public static class ResourcesSource extends InputSource {
		private final ResourceManager mResources;
		private final int mResourceId;
		/**
		 * Constructor
		 */
		public ResourcesSource(ResourceManager resources, int resourceId) {
			mResources = resources;
			mResourceId = resourceId;
		}

		@Override
		GifInfoHandle open() throws IOException {
			String path = null;
			try {
				path = mResources.getMediaPath(mResourceId);
			} catch (NotExistException e) {
				e.printStackTrace();
			} catch (WrongTypeException e) {
				e.printStackTrace();
			}
			return new GifInfoHandle(mResources.getRawFileEntry(path).openRawFileDescriptor());
		}
	}

	public static class AssetFileDescriptorSource extends InputSource {
		private final RawFileDescriptor mRawFileDescriptor;

		public AssetFileDescriptorSource(RawFileDescriptor rawFileDescriptor) {
			mRawFileDescriptor = rawFileDescriptor;
		}

		@Override
		GifInfoHandle open() throws IOException {
			return new GifInfoHandle(mRawFileDescriptor);
		}
	}
}
